package net.xdclass.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import net.xdclass.config.RabbitMQConfig;
import net.xdclass.enums.BizCodeEnum;
import net.xdclass.enums.ProductOrderStateEnum;
import net.xdclass.enums.StockTaskStateEnum;
import net.xdclass.exception.BizException;
import net.xdclass.feign.ProductOrderFeignService;
import net.xdclass.mapper.ProductMapper;
import net.xdclass.mapper.ProductTaskMapper;
import net.xdclass.model.ProductDO;
import net.xdclass.model.ProductMessage;
import net.xdclass.model.ProductTaskDO;
import net.xdclass.request.LockProductRequest;
import net.xdclass.request.OrderItemRequest;
import net.xdclass.service.ProductService;
import net.xdclass.utils.JsonData;
import net.xdclass.vo.ProductVO;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import springfox.documentation.spring.web.json.Json;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ProductTaskMapper productTaskMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitMQConfig rabbitMQConfig;

    @Autowired
    private ProductOrderFeignService orderFeignService;

    @Override
    public Map<String, Object> page(int page, int size) {
        Page<ProductDO> pageInfo = new Page<>(page, size);
        IPage<ProductDO> productDOIPage = productMapper.selectPage(pageInfo, null);
        Map<String, Object> resultMap = new HashMap<>(3);
        resultMap.put("total_record", productDOIPage.getTotal());
        resultMap.put("total_page", productDOIPage.getPages());
        resultMap.put("current_data", productDOIPage.getRecords().stream()
                .map(item -> beanProcess(item))
                .collect(Collectors.toList())
        );

        return resultMap;
    }

    @Override
    public ProductVO detail(long id) {
        ProductDO productDO = productMapper.selectById(id);
        ProductVO productVO = beanProcess(productDO);

        return productVO;
    }

    @Override
    public List<ProductVO> findProductsByIdBatch(List<Long> productIdList) {
        List<ProductDO> productDOList = productMapper.selectList(new QueryWrapper<ProductDO>().in("id", productIdList));
        List<ProductVO> productVOList = productDOList.stream().map(obj -> beanProcess(obj)).collect(Collectors.toList());

        return productVOList;
    }

    @Override
    public JsonData lockProductStock(LockProductRequest lockProductRequest) {
         String outTradeNo = lockProductRequest.getOrderOutTradeNo();
         List<OrderItemRequest> itemList = lockProductRequest.getOrderItemRequestList();

         List<Long> productIdList = itemList.stream().map(OrderItemRequest::getProductId)
                 .collect(Collectors.toList());
         List<ProductVO> productVOList = findProductsByIdBatch(productIdList);
         Map<Long, ProductVO> productMap = productVOList.stream()
                 .collect(Collectors.toMap(ProductVO::getId, Function.identity()));

         itemList.stream().forEach(item -> {
             int rows = productMapper.lockProductStock(item.getProductId(), item.getBuyNum());
             if (rows != 1) {
                 throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL);
             } else {
                 ProductVO productVO = productMap.get(item.getProductId());
                 ProductTaskDO productTaskDO = new ProductTaskDO();
                 productTaskDO.setBuyNum(item.getBuyNum());
                 productTaskDO.setProductId(item.getProductId());
                 productTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
                 productTaskDO.setProductName(productVO.getTitle());
                 productTaskDO.setOutTradeNo(outTradeNo);
                 productTaskMapper.insert(productTaskDO);
                log.info("商品庫鎖定-插入商品product_task成功: {}", productTaskDO);

                 ProductMessage productMessage = new ProductMessage();
                 productMessage.setOutTradeNo(outTradeNo);
                 productMessage.setTaskId(productTaskDO.getId());

                 rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(), rabbitMQConfig.getStockReleaseRoutingKey(), productMessage);
                 log.info("商品庫存鎖定信息延遲消息發送成功: {}", productMessage);

             }
         });

         return JsonData.buildSuccess();
    }

    @Override
    public boolean releaseProductStock(ProductMessage productMessage) {
        ProductTaskDO taskDO = productTaskMapper.selectOne(new QueryWrapper<ProductTaskDO>()
                .eq("id", productMessage.getTaskId())
        );
        if (taskDO == null) {
            log.warn("工作單不存在, 消息體為: {}", productMessage);
            return true;
        }

        if (taskDO.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())) {
            JsonData jsonData = orderFeignService.queryProductOrderState(productMessage.getOutTradeNo());
            if (jsonData.getCode() == 0) {
                String state = jsonData.getData().toString();
                if (ProductOrderStateEnum.NEW.name().equalsIgnoreCase(state)) {
                    log.warn("訂單狀態是NEW, 返回給消息隊列, 重新投遞: {}", productMessage);
                    return false;
                } else if (ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)) {
                    taskDO.setLockState(StockTaskStateEnum.FINISH.name());
                    productTaskMapper.update(taskDO, new QueryWrapper<ProductTaskDO>()
                            .eq("id", productMessage.getTaskId())
                    );
                    log.info("訂單已經支付, 修改庫存鎖定工作單FINISH狀態: {}", productMessage);
                    return true;
                }
            }

            log.warn("訂單不存在, 或者訂單被取消, 确認消息, 修改task狀態為CANCEL,恢复商品庫存, message: {}", productMessage);
            taskDO.setLockState(StockTaskStateEnum.CANCEL.name());
            productTaskMapper.update(taskDO, new QueryWrapper<ProductTaskDO>()
                    .eq("id", productMessage.getTaskId())
            );
            productMapper.unlockProductStock(taskDO.getProductId(), taskDO.getBuyNum());
            return true;
        } else {
            log.warn("工作單狀態不是LOCK state = {}, 消息體={}", taskDO.getLockState(), productMessage);
            return true;
        }
    }

    private ProductVO beanProcess(ProductDO productDO) {
        ProductVO productVO = new ProductVO();
        BeanUtils.copyProperties(productDO, productVO);
        productVO.setStock(productDO.getStock() - productDO.getLockStock());

        return productVO;
    }
}
